from django.test import TestCase

# Create your tests here.
from django.utils.timezone import datetime,timedelta
from rest_framework.test import APITestCase
from accounts.models import User
from .serializer import *
from rest_framework.authtoken.models import Token
from .models import Address

class MixinMockUser:
    user = None

    def _mock_user_data(self):
        data = {
            "username": "username_1",
            "password": "password_1",
            "mobile": "mobile_1",
        }
        self.user = User.objects.create_user(**data)
        self.address = Address.objects.create(
            user=self.user,
            name="Gavin",
            tel="11111",
            street="中国。北京"
        )

class AccountsAPITest(APITestCase):
    base_url = '/accounts/user'

    # 2. 有获取验证码接口
    def test_get_code(self):

    # POST / get_code /
    # 1接口返回200
        url = self.base_url + '/get_code/'
        data={
            'mobile':'138777999'
        }

        _code = []  # 保存验证码

        for i in range(5):
            response=self.client.post(url,data)
            self.assertEqual(response.status_code,200)
            code=response.data['code']

            _code.append(code)
        self.assertEquals(len(set(_code)),5)

    def test_reg(self):
        url=self.base_url + '/reg/'
    # 3.注册的接口POST / reg /
    # 1.应该输入全部字段
        data={
            'username':'zy',
            'mobile':'138777999',
            'password':'123456',
            'code':'',
        }

        code_response=self.client.post(self.base_url+'/get_code/',data)
        code=code_response.data['code']
        data['code']=code
        response=self.client.post(url,data)
        # 2.输入的数据正确，接口返回200。同时返回用户的数据（可选）
        self.assertEqual(response.status_code,200)
    # 3.数据库中添加新的用户，除了密码字段，其他字段和用户输入的一样
        user=User.objects.first()
        #有用户被创造
        self.assertTrue(user)
        self.assertEqual(user.username,data['username'])
        self.assertEqual(user.mobile,data['mobile'])
        # 4.数据库中密码，和用户输入的密码不一样
        self.assertNotEqual(user.password,data['password'])
        # 5.使用 ** django功能 **，密码可以通过验证
        self.assertTrue(user.check_password(data['password']))


        # 6.如果用户名重复、手机号重复、验证码错误，接口400，返回错误提示
        response = self.client.post(url, data)
        self.assertEqual(response.status_code,400)

        #用户名有错误
        self.assertTrue(response.data.get('username'),False)
        #手机号错误
        self.assertTrue(response.data.get('mobile'), False)
        #验证码错误
        self.assertTrue(response.data.get('code'), False)

    def test_login(self):
        url = self.base_url+'/login/'
        data = {
            'username': 'zy',
            'password': '123456',
            'mobile': '138777555',
        }
        # mock 数据
        user = User.objects.create_user(**data)
        # 登录接口 post，/login/
        # 用户输入的密码是明文
        response = self.client.post(url,data)
        # 用户登录失败，错误提示,用户名和密码不匹配，返回400
        response = self.client.post(url, {**data,**{'password':data['password']+'0'}}) #错误密码
        self.assertContains(response, '用户名和密码不匹配',status_code=400)
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, data['username'])
        # 获取用户的token
        token = Token.objects.get(user=user)  # 此处的token是实例，不是身份凭证
        token.key
        self.assertContains(response, token.key)

class AddressAPITest(APITestCase):
    """收货地址测试"""
    base_url = "/accounts/address"
    user = None

    def setUp(self):
        self._mock_user_data()
        self.client.force_login(self.user)

    def _mock_user_data(self):
        data = {
            "username": "username_1",
            "password": "password_1",
            "mobile": "mobile_1",
        }
        self.user = User.objects.create_user(**data)
        self.address = Address.objects.create(
            user=self.user,
            name="Gavin",
            tel="11111",
            street="中国。北京"
        )

    # 1.查 GET
    def test_get(self):
        pass
    #     #    1.接口返回200
        url = self.base_url+'/'
        response = self.client.get(url)
        self.assertEqual(response.status_code,200)

    #    # 2.返回数据结构，和序列化器相同
        queryset = Address.objects.all()
        serializer = AddressSerializer(queryset,many=True)
        self.assertEqual(response.data['results'], serializer.data)

    def test_delete(self):
        pass
        # 2.删 DELETE/{pk}/
        url = self.base_url +f'/{self.address.id}/'
        response = self.client.delete(url)
        #     1.接口返回204
        self.assertEqual(response.status_code,204)
        #     2.删除之后，数据库数量减少
        self.assertEqual(Address.objects.all().count(),0)
        #     3.删除之后，改pk的数据不存在
        with self.assertRaises(Address.DoesNotExist):
            obj = Address.objects.get(id=self.address.id)

    def test_put(self):
        # 3.改 PUT/{pk}/
        data = {'name':self.address.name+'_new'}
        url = self.base_url + f'/{self.address.id}/'
        response = self.client.patch(url, data)
        #     1.接口返回200
        self.assertEqual(response.status_code,200)
        #     2.修改之后，数据库里的数据和提交数据一致
        obj = Address.objects.get(id=self.address.id)
        self.assertEqual(obj.name, data['name'])

    def test_post(self):
        # 4.增  POST
        pass
        queryset = Address.objects.all()
        count_bak = queryset.count()
        data = {'name': 'zy',
                'tel': '13855559999',
                'street':'中国，北京',}
        url = self.base_url + f'/'
        response = self.client.post(url, data)
        #     1.返回接口201
        self.assertEqual(response.status_code, 201,response.data)
        #     2.数据增加，内容和提交的数据一致
        self.assertEqual(queryset.count(), count_bak+1)
        obj = Address.objects.last()
        for key in data.keys():
            self.assertEqual(getattr(obj, key), data[key])

    def test_403(self):
        self.client.logout()
        # 5.鉴权：
        #     以上接口，如果直接访问，返回403
        url = self.base_url +'/'
        response = self.client.get(url)
        self.assertEqual(response.status_code,403)
        #     如果登录之后访问，正常返回
        self.client.force_login(self.user)
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def test_filter(self):
        pass
        url = self.base_url + '/'
        # 过滤
        data = {
            "username": "username_2",
            "password": "password_2",
            "mobile": "mobile_2",
        }
        user_B=User.objects.create(**data)
        user_A=self.user


        self.client.force_login(user_A)
        response_A=self.client.get(url)
        self.assertEqual(response_A.status_code,200)

        self.client.force_login(user_B)
        response_B = self.client.get(url)
        self.assertEqual(response_B.status_code, 200)

        self.assertNotEqual(response_A.data,response_B.data)

class CheckInAPITest(MixinMockUser,APITestCase):
    base_url = "/accounts/check"

    def setUp(self):
        self._mock_user_data()
        self.client.force_login(self.user)

    def test_get(self):
        # - 查看签到情况 GET / check /
        url = self.base_url + '/'
        self.client.logout()
        respone = self.client.get(url)
        #     - 匿名用户返回403
        self.assertEqual(respone.status_code, 403)
        #     - 登陆后访问 返回200
        self.client.force_login(self.user)
        respone = self.client.get(url)
        self.assertEqual(respone.status_code, 200)

    def test_check(self):
        pass
        #
        # - 正常签到 POST / check /
        # 获取当前用户的签到记录
        check_in_1, is_create = CheckIn.objects.get_or_create(user=self.user)
        url = self.base_url + '/'
        response = self.client.post(url)  # 第一次签到
        # 获取当前用户的签到记录
        check_in_2 = CheckIn.objects.get(user=self.user)
        #     - 签到次数 + 1，签到时间今天
        self.assertEqual(check_in_2.count, check_in_1.count + 1)
        self.assertEqual(check_in_2.datetime.date(), datetime.now().date())
        #
        # - 重复签到 POST / check /
        for i in range(3):
            response = self.client.post(url)  # 第N次签到
            check_in_3 = CheckIn.objects.get(user=self.user)
            self.assertEqual(check_in_3.count, check_in_2.count)
            self.assertEqual(check_in_3.datetime, check_in_2.datetime)

    def test_combo(self):
        pass
        url = self.base_url + '/'
        # - 连续签到
        # - 循环6次，
        check_in_0, is_create = CheckIn.objects.get_or_create(user=self.user)
        for i in range(6):
            check_in_1, is_create = CheckIn.objects.get_or_create(user=self.user)
            check_in_1.datetime = datetime.now() - timedelta(days=1)
            check_in_1.save()
            #     1.上次签到时间改为昨天，
            #     2.进行签到
            url = self.base_url + '/'
            response = self.client.post(url)
            check_in_2 = CheckIn.objects.get(user=self.user)
            self.assertEqual(check_in_2.count, check_in_1.count + 1)
        #     3.断言：签到次数 + 1
        check_in_2 = CheckIn.objects.get(user=self.user)
        self.assertEqual(check_in_2.count, check_in_0.count + 6)
        #     断言： 签到次数 + 6
        # - 中断签到
        #     1.上次签到时间改为前天
        check_in_1, is_create = CheckIn.objects.get_or_create(user=self.user)
        check_in_1.datetime = datetime.now() - timedelta(days=2)
        check_in_1.save()

        #     2.进行签到
        response = self.client.post(url)  # 第一次签到
        check_in_2 = CheckIn.objects.get(user=self.user)

        #     3.签到次数 = 0 + 1
        self.assertEqual(check_in_2.count, 0 + 1)
        self.assertEqual(check_in_2.datetime.date(), datetime.now().date())